package com.contract.common.util;

import com.artofsolving.jodconverter.DocumentConverter;
import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter;
import com.contract.common.enums.SignTypeEnum;
import com.contract.common.error.BizException;
import com.contract.common.error.JsonReturnCode;
import com.contract.pojo.bo.BizFile;
import com.contract.pojo.dto.ContractSignDto;
import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;
import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 文件操作工具
 *
 * @author liw
 * @version 1.0
 * @date 2022/6/28 15:20
 */
@Slf4j
public class FileUtil {

    public static final String PDF_SUFFIX = "pdf";

    public static final String DOCX_SUFFIX = "docx";

    public static final String BRACE_LEFT = "{";

    public static final String BRACE_RIGHT = "}";

    public static final Map<String, String> USER_INFO_TEST = new HashMap<>();

    static {
        USER_INFO_TEST.put("userName", "卡卡罗特");
        USER_INFO_TEST.put("contractNo", "HTNO123456");
        USER_INFO_TEST.put("address", "贝吉塔行星普兰特大区靠山屯村头大树下");
        USER_INFO_TEST.put("sex", "男");
        USER_INFO_TEST.put("cardNo", "147852369147852367");
        USER_INFO_TEST.put("phone", "12345678901");
        USER_INFO_TEST.put("currentAddress", "太阳系土卫六泰坦星球蔡徐村池塘边");
        USER_INFO_TEST.put("workPlace", "超级塞亚星有限公司");
        USER_INFO_TEST.put("email", "123456789@qq.com");
        USER_INFO_TEST.put("contactPhone", "12345678901");
        USER_INFO_TEST.put("start", "2000-01-01");
        USER_INFO_TEST.put("end", "2999-12-31");
//        USER_INFO_TEST.put("wages", "6000");
    }

    /**
     * pdf添加value
     *
     * @param dto 数据
     */
    public static void addPdfValue(ContractSignDto dto) {
        try {
            FileInputStream fileInputStream = new FileInputStream(dto.getFromPath());
            // 原PDF文件
            PdfReader reader = new PdfReader(IOUtils.toByteArray(fileInputStream));
            // 输出的PDF文件内容
            PdfStamper stamper = new PdfStamper(reader, Files.newOutputStream(Paths.get(dto.getOutPath())));
            // 字体 来源于 itext-asian jar包
            BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", true);
            PdfGState gs = new PdfGState();
            // 设置透明度
            gs.setFillOpacity(0.5f);
            gs.setStrokeOpacity(0.3f);

            for (ContractSignDto.ImgInfo imgInfo : dto.getImgInfoList()) {
                // 内容上层
                PdfContentByte content = stamper.getOverContent(imgInfo.getPage());
                content.beginText();
                // 字体添加透明度
                content.setGState(gs);
                // 添加字体大小等
                content.setFontAndSize(baseFont, 12);
                // 添加范围
                content.showTextAligned(Element.ALIGN_JUSTIFIED_ALL, imgInfo.getValue(), imgInfo.getX(), imgInfo.getY(), 0);
                content.endText();
            }
            // 关闭
            stamper.close();
            reader.close();
        } catch (Exception e) {
            log.error("addPdfValue", e);
            throw new BizException(JsonReturnCode.SIGN_ERROR);
        }
    }

    public static void pdfAddImg(ContractSignDto dto) {
        Document document = new Document();
        try {
            File file = new File(dto.getFromPath());
            //合成后的文件
            FileOutputStream outputStream = new FileOutputStream(dto.getOutPath());
            PdfReader reader = new PdfReader(new FileInputStream(file));
            PdfStamper stamper = new PdfStamper(reader, outputStream);

            // 字体 来源于 itext-asian jar包
            BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", true);

            for (ContractSignDto.ImgInfo imgInfo : dto.getImgInfoList()) {

                // 内容上层
                PdfContentByte content = stamper.getOverContent(imgInfo.getPage());
                if (SignTypeEnum.DATE.getKey().equals(imgInfo.getType())) {
                    content.beginText();
                    PdfGState pdfGState = new PdfGState();
                    // 设置透明度
                    pdfGState.setFillOpacity(0.6f);
                    pdfGState.setStrokeOpacity(0.2f);
                    // 字体添加透明度
                    content.setGState(pdfGState);
                    // 添加字体大小等
                    content.setFontAndSize(baseFont, 12);
                    // 添加范围
                    content.showTextAligned(Element.ALIGN_JUSTIFIED_ALL, imgInfo.getValue(), imgInfo.getX(), imgInfo.getY(), 0);
                    content.endText();
                } else {
                    content.saveState();
                    com.itextpdf.text.Image contractSealImg = com.itextpdf.text.Image.getInstance(imgInfo.getImgPath());
                    PdfGState pdfGState = new PdfGState();
                    // 设置透明度
                    pdfGState.setFillOpacity(1F);
                    content.setGState(pdfGState);
                    contractSealImg.setAbsolutePosition(imgInfo.getX(), imgInfo.getY());  //设置图片位置
                    contractSealImg.scaleAbsolute(imgInfo.getWidth(), imgInfo.getHeight());  //设置图片大小
                    content.addImage(contractSealImg);  //将图片添加到pdf文件
                    content.restoreState();
                }
            }
            stamper.setFormFlattening(true);
            stamper.close();
            reader.close();
            outputStream.close();
        } catch (Exception e) {
            log.error("pdfAddImg", e);
            throw new BizException(JsonReturnCode.SIGN_ERROR);
        } finally {
            document.close();
        }
    }

    /**
     * 反转图像
     *
     * @param path
     * @param out
     */
    public static void rotate(String path, String out) {
        try {
            BufferedImage originalImage = ImageIO.read(new File(path));
            // 获取原始图像的宽高信息
            int width = originalImage.getWidth();
            int height = originalImage.getHeight();
            // 创建新的 BufferedImage 对象，大小为旋转后的图像尺寸
            BufferedImage rotatedImage = new BufferedImage(height, width, 6);
            // 获取 Graphics2D 上下文
            Graphics2D g2d = rotatedImage.createGraphics();
            // 设置旋转角度（逆时针）
            double radians = Math.PI / 2;
            // 执行旋转操作
            g2d.rotate(-radians);
            // 绘制原始图像到旋转后的位置
            g2d.drawImage(originalImage, -width, 0, null);
            // 清除 Graphics2D 上下文
            g2d.dispose();
            // 输出旋转后的图像
            File outputFile = new File(out);
            ImageIO.write(rotatedImage, FileUtil.getSuffix(path), outputFile);
        } catch (Exception e) {
            log.error("rotate:", e);
            throw new BizException(JsonReturnCode.IMG_ROTATE_ERR);
        }
    }

    public static void wordToPdf(String sourceFile, String pdfFile) {
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().startsWith("win")) {
            try {
                File inputWord = new File(sourceFile);
                DocumentType doc;
                if (sourceFile.toLowerCase().contains("docx")) {
                    doc = DocumentType.DOCX;
                } else {
                    doc = DocumentType.DOC;
                }
                File outputFile = new File(pdfFile);
                InputStream docxInputStream = Files.newInputStream(inputWord.toPath());
                OutputStream outputStream = Files.newOutputStream(outputFile.toPath());
                IConverter converter = LocalConverter.builder().build();
                converter.convert(docxInputStream).as(doc).to(outputStream).as(DocumentType.PDF).execute();
                converter.shutDown();
                docxInputStream.close();
                outputStream.close();
            } catch (Exception e) {
                log.error("wordToPdf:", e);
                throw new BizException(JsonReturnCode.DOC_PDF_ERR);
            }
        } else {
            OpenOfficeConnection connection = new SocketOpenOfficeConnection("127.0.0.1", 8100);
            try {
                connection.connect();
                DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
                converter.convert(new File(sourceFile), new File(pdfFile));
                connection.disconnect();
            } catch (Exception e) {
                log.error("wordToPdf:", e);
                throw new BizException(JsonReturnCode.DOC_PDF_ERR);
            }
        }

    }

    public static void addWordValue(String path, String outPath, Map<String, String> map) {
        // 加载doc文件
        try {
            XWPFDocument doc = new XWPFDocument(new FileInputStream(path));
            // 修改文本内容

            StringBuilder sb = new StringBuilder();
            boolean flag = false;
            int pos = 0;
            for (XWPFParagraph paragraph : doc.getParagraphs()) {
                for (XWPFRun run : paragraph.getRuns()) {
                    String text = run.getText(pos);
                    if (CommonUtil.isEmpty(text)) {
                        continue;
                    }
                    text = text.trim();
                    if (text.startsWith(BRACE_LEFT)) {
                        flag = true;
                        sb.setLength(0);
                    }
                    if (!flag) {
                        continue;
                    }
                    sb.append(text);
                    String value = "";
                    if (text.endsWith(BRACE_RIGHT)) {
                        flag = false;
                        value = map.get(sb.toString().replace(BRACE_LEFT, "").replace(BRACE_RIGHT, ""));
                    }
                    run.setText(value, pos);
                }
            }
            // 保存修改后的doc文件
            FileOutputStream out = new FileOutputStream(outPath);
            doc.write(out);
            out.close();
            // 关闭doc文件
            doc.close();
        } catch (IOException e) {
            log.error("addDocValue:", e);
            throw new BizException(JsonReturnCode.REPALCE_DOC_ERR);
        }
    }

    public static BizFile file2Local(MultipartFile file, String rootPath) {
        String fileName = FileUtil.makeFileName(file.getOriginalFilename());
        String filePath = FileUtil.createFilePath(rootPath);
        try {
            File dest = new File(rootPath + filePath, fileName);
            file.transferTo(dest);
            BizFile bizFile = new BizFile();
            bizFile.setName(file.getOriginalFilename());
            bizFile.setPath(filePath + fileName);
            return bizFile;
        } catch (IOException e) {
            e.printStackTrace();
            throw new BizException(JsonReturnCode.FILE_UPLOAD_ERROR);
        }
    }

    /**
     * @return 新文件名
     */
    public static String createFilePath(String root) {
        String s = DateUtil.date2Str(LocalDateTime.now(), DateUtil.DATE_YMD);
        File f = new File(root + s);
        if (!f.exists()) {
            f.mkdirs();
        }
        return s + File.separator;
    }

    public static byte[] file2Bytes(File file) {
        byte[] imageBytes = null;
        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            imageBytes = new byte[fileInputStream.available()];
            fileInputStream.read(imageBytes);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BizException(JsonReturnCode.FILE_DOWNLOAD_ERROR);
        }
        return imageBytes;
    }

    public static void outFile(HttpServletResponse response, File file) {
        String fileName = file.getName();
        if (!file.exists()) {
            throw new BizException(JsonReturnCode.FILE_DOWNLOAD_ERROR);
        }
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        // 创建缓冲输入流
        OutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            outputStream.write(file2Bytes(file));
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 重新生成文件名
     *
     * @param originalFilename 原文件名
     * @return 新文件名
     */
    public static String makeFileName(String originalFilename) {
        String suffix = "";
        int beginIndex = originalFilename.lastIndexOf(".");
        if (beginIndex > 0) {
            suffix = originalFilename.substring(beginIndex);
        }
        return UUID.randomUUID().toString().replace("-", "") + suffix;
    }

    public static String makeNameByType(String type) {
        return UUID.randomUUID().toString().replace("-", "") + "." + type;
    }

    public static String getSuffix(String path) {
        int i = path.lastIndexOf(".");
        if (i >= 0) {
            return path.substring(i + 1);
        }
        throw new BizException(JsonReturnCode.FILE_NOT_EXIST_ERROR);
    }

    public static String imageToBase64(String imagePath) {
        try {
            File imageFile = new File(imagePath);
            InputStream fileInputStream = new FileInputStream(imageFile);
            byte[] imageBytes = new byte[(int) imageFile.length()];
            fileInputStream.read(imageBytes);
            fileInputStream.close();
            return Base64.getEncoder().encodeToString(imageBytes);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BizException(JsonReturnCode.IMG_ERROR);
        }
    }

}
